package com.example.mybatis.sqlserver.springbootmybatissqlserver.service.impl;

import com.example.mybatis.sqlserver.springbootmybatissqlserver.controller.DeleteCategoryDTO;
import com.example.mybatis.sqlserver.springbootmybatissqlserver.pojo.bean.CategoryBean;
import com.example.mybatis.sqlserver.springbootmybatissqlserver.pojo.bean.CategoryPropertyNameBean;
import com.example.mybatis.sqlserver.springbootmybatissqlserver.pojo.bean.CategoryPropertyValueBean;
import com.example.mybatis.sqlserver.springbootmybatissqlserver.pojo.dto.*;
import com.example.mybatis.sqlserver.springbootmybatissqlserver.repository.ICategoryRepository;
import com.example.mybatis.sqlserver.springbootmybatissqlserver.service.ICategoryService;
import com.example.mybatis.sqlserver.springbootmybatissqlserver.util.Constants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by hzy on 2019/2/19.
 */
@Service
public class CategoryServiceImpl implements ICategoryService {
    @Autowired
    ICategoryRepository repository;

    @Override
    public WebResultBean<GetCategoryDTO> addCategory(AddCategoryDTO dto) {
        WebResultBean<GetCategoryDTO> webResultBean = new WebResultBean<>();
        CategoryBean parentCategory = null;
        if (dto.parentCategoryId != null){
            parentCategory = repository.findCategoryById(dto.parentCategoryId);
            //
            if (parentCategory == null){
                webResultBean.setCodeAndMsg(Constants.RespCode.FAILED,Constants.RespMsg.FAILED);
                return webResultBean;
            }
        }
        //
        CategoryBean categoryBean = CategoryBean.from(dto);
        if (parentCategory != null){
            categoryBean.setLevel(parentCategory.getLevel() + 1);
        }else {
            categoryBean.setLevel(0);
        }

        //
        if (repository.addCategory(categoryBean)){
            GetCategoryDTO getCategoryDTO = new GetCategoryDTO();
            getCategoryDTO.categoryId = categoryBean.getId();
            getCategoryDTO.level = categoryBean.getLevel();
            getCategoryDTO.categoryName = categoryBean.getName();

            webResultBean.code = Constants.RespCode.SUCCESS;
            webResultBean.msg = Constants.RespMsg.SUCCESS;
            webResultBean.data = getCategoryDTO;
        }else {
            webResultBean.code = Constants.RespCode.FAILED;
            webResultBean.msg = Constants.RespMsg.FAILED;
        }
        return webResultBean;
    }

    @Override
    public WebResultBean<Boolean> updateCategory(EditCategoryDTO dto) {
        WebResultBean<Boolean> webResultBean = new WebResultBean<>();
        CategoryBean categoryById = repository.findCategoryById(dto.categoryId);
        if (categoryById == null){
            webResultBean.data = false;
            webResultBean.setCodeAndMsg(Constants.RespCode.FAILED,Constants.RespMsg.FAILED);
            return webResultBean;
        }

        CategoryBean bean = CategoryBean.from(dto);
        if (repository.updateCategory(bean)){
            webResultBean.setCodeAndMsg(Constants.RespCode.SUCCESS,Constants.RespMsg.SUCCESS);
            webResultBean.data = true;
        }else {
            webResultBean.data = false;
            webResultBean.setCodeAndMsg(Constants.RespCode.FAILED,Constants.RespMsg.FAILED);
        }
        return webResultBean;
    }

    @Override
    public WebResultBean<List<GetCategoryDTO>> getCategoriesByParentId(String parentId) {
        WebResultBean<List<GetCategoryDTO>> webResultBean = new WebResultBean<>();
        CategoryBean categoryById = repository.findCategoryById(parentId);
        //
        if (categoryById == null){
            webResultBean.data = new ArrayList<>(0);
            webResultBean.setCodeAndMsg(Constants.RespCode.FAILED,Constants.RespMsg.FAILED);
            return webResultBean;
        }

        //
        List<CategoryBean> categoryBeans = repository.findCategoryByParentId(parentId);
        List<GetCategoryDTO> result = null;
        if (categoryBeans != null && ! categoryBeans.isEmpty()){
            result = categoryBeans.stream()
                    .filter(categoryBean -> ! categoryBean.getIsDelete())
                    .map(CategoryBean::toGetCategoryDTO).collect(Collectors.toList());
        }

        //
        if (result == null){
            webResultBean.data = new ArrayList<>(0);
        }else {
            webResultBean.data = result;
        }
        webResultBean.setCodeAndMsg(Constants.RespCode.SUCCESS,Constants.RespMsg.SUCCESS);
        return webResultBean;
    }


    @Override
    public WebResultBean<List<GetCategoryTreeDTO>> getCategoryTree() {
        WebResultBean<List<GetCategoryTreeDTO>> webResultBean = new WebResultBean<>();

        List<CategoryBean> allCategory = repository.findAllCategory();
        if (allCategory == null || allCategory.isEmpty()){
            webResultBean.data = new ArrayList<>(0);
        }else {
            List<GetCategoryTreeDTO> collect = allCategory.stream()
                    .map(CategoryBean::GetCategoryTreeDTO).collect(Collectors.toList());

            // 子部门需要在全部的部门信息中寻找
            List<GetCategoryTreeDTO> categoryTreeDTOS = generateCategoryTree(null,collect); // 一级列名的 parentId 为 null
            if (categoryTreeDTOS == null){
                webResultBean.data = new ArrayList<>(0);
            }else {
                webResultBean.data = categoryTreeDTOS;
            }
        }
        webResultBean.setCodeAndMsg(Constants.RespCode.SUCCESS,Constants.RespMsg.SUCCESS);
        return webResultBean;
    }

    private List<GetCategoryTreeDTO> generateCategoryTree(String categoryParentId,List<GetCategoryTreeDTO> allCategory) {
        List<GetCategoryTreeDTO> subList = new ArrayList<>();
        for (GetCategoryTreeDTO category : allCategory) {
            //查找获取当前目录的直接子目录
            if ((category.layer == 0 && categoryParentId == null)
                    || category.parentId != null && category.parentId.equals(categoryParentId)){
                //
                category.children = generateCategoryTree(category.categoryId,allCategory);
                //
                subList.add(category);
            }
        }

        if (subList.isEmpty()){
            return null;
        }
        return subList;
    }

    @Override
    public WebResultBean<GetCategoryDTO> findCategory(String categoryId) {
        WebResultBean<GetCategoryDTO> webResultBean = new WebResultBean<>();
        CategoryBean categoryById = repository.findCategoryById(categoryId);
        if (categoryById != null){
            webResultBean.setCodeAndMsg(Constants.RespCode.SUCCESS,Constants.RespMsg.SUCCESS);
            webResultBean.data = CategoryBean.toGetCategoryDTO(categoryById);
        }else {
            webResultBean.setCodeAndMsg(Constants.RespCode.FAILED,Constants.RespMsg.FAILED);
        }
        return webResultBean;
    }

    @Override
    public WebResultBean<Boolean> deleteCategory(DeleteCategoryDTO dto) {
        WebResultBean<Boolean> webResultBean = new WebResultBean<>();
        //
        CategoryBean categoryById = repository.findCategoryById(dto.categoryId);
        if (categoryById == null){
            webResultBean.data = false;
            webResultBean.setCodeAndMsg(Constants.RespCode.FAILED,Constants.RespMsg.FAILED);
            return webResultBean;
        }else {
            // 默认软删除
            if (repository.softDeleteCategoryById(dto.categoryId)){
                webResultBean.data = true;
                webResultBean.setCodeAndMsg(Constants.RespCode.SUCCESS,Constants.RespMsg.SUCCESS);
            }else {
                webResultBean.data = false;
                webResultBean.setCodeAndMsg(Constants.RespCode.FAILED,Constants.RespMsg.FAILED);
            }
        }
        return webResultBean;
    }

    @Override
    public WebResultBean<List<GetPropertyDTO>> listCategoryPropertyName(String categoryId) {
        WebResultBean<List<GetPropertyDTO>> webResultBean = new WebResultBean<>();
        //
        List<CategoryPropertyNameBean> result = repository.listCategoryPropertyName(categoryId);
        if (result != null && ! result.isEmpty()){
            webResultBean.data = result.stream().map(CategoryPropertyNameBean::toGetPropertyDTO).collect(Collectors.toList());
        }else {
            webResultBean.data = new ArrayList<>();
        }
        webResultBean.setCodeAndMsg(Constants.RespCode.SUCCESS,Constants.RespMsg.SUCCESS);
        return webResultBean;
    }

    @Override
    public WebResultBean<Boolean> addCategoryProperty(AddCategoryPropertyDTO dto) {
        WebResultBean<Boolean> webResultBean = new WebResultBean<>();

        // 检查类目是否存在
        CategoryBean categoryById = repository.findCategoryById(dto.categoryId);
        if (categoryById == null){
            webResultBean.setCodeAndMsg(Constants.RespCode.FAILED,Constants.RespMsg.FAILED);
            webResultBean.data = false;
            return webResultBean;
        }

        // TODO: 2019/2/21 属性名重复的问题?
        CategoryPropertyNameBean bean = CategoryPropertyNameBean.from(dto);
        if (repository.addCategoryProperty(bean)){
            webResultBean.setCodeAndMsg(Constants.RespCode.SUCCESS,Constants.RespMsg.SUCCESS);
            webResultBean.data = true;
        }else {
            webResultBean.setCodeAndMsg(Constants.RespCode.SUCCESS,Constants.RespMsg.SUCCESS);
            webResultBean.data = false;
        }
        return webResultBean;
    }

    @Override
    public WebResultBean<Boolean> updateCategoryPropertyName(EditCategoryPropertyDTO dto) {
        WebResultBean<Boolean> webResultBean = new WebResultBean<>();
        //
        CategoryPropertyNameBean bean = CategoryPropertyNameBean.from(dto);
        updateCategoryProperty(webResultBean, bean);
        return webResultBean;
    }

    @Override
    public WebResultBean<Boolean> setCategoryPropertyNameIsShow(SetCategoryPropertyNameIsShowDTO dto) {
        WebResultBean<Boolean> webResultBean = new WebResultBean<>();
        //
        CategoryPropertyNameBean bean = CategoryPropertyNameBean.from(dto);
        updateCategoryProperty(webResultBean, bean);
        return webResultBean;
    }

    private void updateCategoryProperty(WebResultBean<Boolean> webResultBean, CategoryPropertyNameBean bean) {
        if (repository.updateCategoryPropertyName(bean)){
            webResultBean.setCodeAndMsg(Constants.RespCode.SUCCESS,Constants.RespMsg.SUCCESS);
            webResultBean.data = true;
        }else {
            webResultBean.setCodeAndMsg(Constants.RespCode.FAILED,Constants.RespMsg.FAILED);
            webResultBean.data = false;
        }
    }

    @Override
    public WebResultBean<GetPropertyDTO> findCategoryPropertyById(String propertyId) {
        WebResultBean<GetPropertyDTO> webResultBean = new WebResultBean<>();
        CategoryPropertyNameBean bean = repository.findCategoryPropertyById(propertyId);
        if (bean != null){
            webResultBean.setCodeAndMsg(Constants.RespCode.SUCCESS,Constants.RespMsg.SUCCESS);
            webResultBean.data = CategoryPropertyNameBean.toGetPropertyDTO(bean);
        }else {
            webResultBean.setCodeAndMsg(Constants.RespCode.FAILED,Constants.RespMsg.FAILED);
        }
        return webResultBean;
    }


    @Override
    public WebResultBean<Boolean> addCategoryPropertyValue(AddCategoryPropertyValueDTO dto) {
        // TODO: 2019/2/21 propertyValue 是否不能重复?
        WebResultBean<Boolean> webResultBean = new WebResultBean<>();
        CategoryPropertyValueBean valueBean = CategoryPropertyValueBean.from(dto);
        if (repository.addCategoryPropertyValue(valueBean)){
            webResultBean.setCodeAndMsg(Constants.RespCode.SUCCESS,Constants.RespMsg.SUCCESS);
            webResultBean.data = true;
        }else {
            webResultBean.setCodeAndMsg(Constants.RespCode.FAILED,Constants.RespMsg.FAILED);
            webResultBean.data = false;
        }
        return webResultBean;
    }

    @Override
    public WebResultBean<Boolean> editCategoryPropertyValue(EditCategoryPropertyValueDTO dto) {
        WebResultBean<Boolean> webResultBean = new WebResultBean<>();
        //
        CategoryPropertyValueBean bean = CategoryPropertyValueBean.from(dto);
        updateCategoryPropertyValue(webResultBean, bean);
        return webResultBean;
    }

    @Override
    public WebResultBean<Boolean> setCategoryPropertyValueIsShow(SetCategoryPropertyValueIsShowDTO dto) {
        WebResultBean<Boolean> webResultBean = new WebResultBean<>();
        //
        CategoryPropertyValueBean bean = CategoryPropertyValueBean.from(dto);
        updateCategoryPropertyValue(webResultBean, bean);
        return webResultBean;
    }

    private void updateCategoryPropertyValue(WebResultBean<Boolean> webResultBean, CategoryPropertyValueBean bean) {
        if (repository.updateCategoryPropertyValue(bean)){
            webResultBean.setCodeAndMsg(Constants.RespCode.SUCCESS,Constants.RespMsg.SUCCESS);
            webResultBean.data = true;
        }else {
            webResultBean.setCodeAndMsg(Constants.RespCode.FAILED,Constants.RespMsg.FAILED);
            webResultBean.data = false;
        }
    }

    @Override
    public WebResultBean<List<GetPropertyValueDTO>> listCategoryPropertyValue(String propertyId) {
        WebResultBean<List<GetPropertyValueDTO>> webResultBean = new WebResultBean<>();
        List<CategoryPropertyValueBean> result = repository.listCategoryPropertyValue(propertyId);
        if (result != null && ! result.isEmpty()){
            webResultBean.data = result.stream().map(categoryPropertyValueBean -> {
                GetPropertyValueDTO dto = new GetPropertyValueDTO();
                dto.categoryPropertyNameId = categoryPropertyValueBean.getFkCategoryPropertyName();
                dto.id = categoryPropertyValueBean.getId();
                dto.isShow = categoryPropertyValueBean.getIsShow();
                dto.propertyValue = categoryPropertyValueBean.getPropertyValue();
                return dto;
            }).collect(Collectors.toList());
        }

        if (webResultBean.data == null){
            webResultBean.data = new ArrayList<>(0);
        }
        webResultBean.setCodeAndMsg(Constants.RespCode.SUCCESS,Constants.RespMsg.SUCCESS);
        return webResultBean;
    }
}
